home *** CD-ROM | disk | FTP | other *** search
/ ...taking it to the Macs! / ...taking it to the Macs!.iso / Extras / ActiveX Mac SDK / ActiveX SDK / Sample Controls / Clock / CClockControl.cpp next >
Encoding:
Text File  |  1996-12-19  |  13.8 KB  |  504 lines  |  [TEXT/CWIE]

  1. // =================================================================================
  2. //
  3. //    CClockControl.cpp                ©1996 Microsoft Corporation All rights reserved.
  4. //
  5. // =================================================================================
  6.  
  7. #include "ocheaders.h"
  8. #include <math.h>
  9. #include "CClockControl.h"
  10.  
  11.  
  12. const Uint16    Shades[2][7] = {    /* not pressed    */ 0xf000, 0xd000, 0xc000, 0x8800, 0x7000, 0x5000, 0x3000,
  13.                                 /* pressed        */ 0xd000, 0xb000, 0x9000, 0x7000, 0x6000, 0x4000, 0x2000 };
  14. const Int16        ShinySpot        = -45;
  15. const Int16        Face_Shade        = 3;
  16. const Int16        HighKey_Shade    = 0;
  17. const Int16        HiMedKey_Shade    = 1;
  18. const Int16        MedHiKey_Shade    = 2;
  19. const Int16        MedKey_Shade    = 3;
  20. const Int16        MedLowKey_Shade    = 4;
  21. const Int16        LowMedKey_Shade    = 5;
  22. const Int16        LowKey_Shade    = 6;
  23.  
  24. const Int32        DefaultIdleTicks    = 60;
  25. const Uint32    DefaultIdleRefCon    = 0;
  26.  
  27.  
  28. #pragma mark === CClockControl::Construction & Destruction ===
  29.  
  30.  
  31. //=--------------------------------------------------------------------------=
  32. //  CClockControl::CClockControl    
  33. //=--------------------------------------------------------------------------=
  34.  
  35. CClockControl::CClockControl(void)
  36. {
  37.     ::GetTime(&mTime);
  38.     mEraseTime = mTime;
  39.     mHandsDirty = 1;
  40.     mFaceDirty = 1;
  41.     mIsPressed = false;
  42.     mIsIdling = false;
  43. }
  44.  
  45.  
  46. //=--------------------------------------------------------------------------=
  47. //  CClockControl::~CClockControl
  48. //=--------------------------------------------------------------------------=
  49.  
  50. CClockControl::~CClockControl()
  51. {
  52. }
  53.  
  54. #pragma mark === CClockControl::IControl Interface ===
  55.  
  56.  
  57. //=--------------------------------------------------------------------------=
  58. //  CClockControl::IControl::Draw
  59. //=--------------------------------------------------------------------------=
  60.  
  61. STDMETHODIMP
  62. CClockControl::Draw( DrawContext* inContext)
  63. {
  64.     if (inContext->DrawAspect != DVASPECT_CONTENT)
  65.         return DV_E_DVASPECT;
  66.  
  67.     //    we are in a context aspect, be sure we are idling
  68.     StartIdling();
  69.  
  70.     mFaceDirty = 1;    //    if we are called to draw from outside then assume we'd better do the whole thing
  71.     DrawMe(&inContext->Location, 1);
  72.     
  73.     return S_OK;
  74. }
  75.  
  76.  
  77. //=--------------------------------------------------------------------------=
  78. //  CClockControl::IControl::DoMouse    
  79. //=--------------------------------------------------------------------------=
  80.  
  81. STDMETHODIMP
  82. CClockControl::DoMouse(MouseEventType inMouseET, PlatformEvent* inEvent)
  83. {
  84. #pragma unused (inEvent)
  85.     ErrorCode    theResult = S_FALSE;
  86.  
  87.     switch (inMouseET)
  88.     {
  89.         case MouseUp:
  90.             mIsPressed = false;
  91.             mFaceDirty = 1;
  92.             DrawAllContexts();
  93.             theResult = S_OK;
  94.             break;
  95.  
  96.         case MouseDown:
  97.           mIsPressed = true;
  98.           mFaceDirty = 1;
  99.           DrawAllContexts();
  100.           theResult = S_OK;
  101.           break;
  102.           
  103.         case MouseEnter:
  104.             InitCursor();  // We'll use the arrow cursor for now.
  105.             break;
  106.     }
  107.     
  108.     return theResult;
  109. }
  110.  
  111.  
  112. //=--------------------------------------------------------------------------=
  113. //  CClockControl::IControl::DoIdle    
  114. //=--------------------------------------------------------------------------=
  115.  
  116. STDMETHODIMP
  117. CClockControl::DoIdle(Uint32 IdleRefCon)
  118. {
  119. #pragma unused(IdleRefCon)
  120.  
  121.     DateTimeRec    NewTime;
  122.  
  123.     ::GetTime(&NewTime);
  124.     mHandsDirty = (NewTime.second != mTime.second || NewTime.minute != mTime.minute
  125.                     || NewTime.hour != mTime.hour) ? 1 : 0;        
  126.     if (mHandsDirty)
  127.     {
  128.         mTime = NewTime;
  129.         DrawAllContexts();
  130.         mContainerSiteP->OnChange(ViewChange);
  131.     }
  132.  
  133.     return S_OK;
  134. }
  135.  
  136.  
  137. #pragma mark === CClockControl::protected methods ===
  138.  
  139. //=--------------------------------------------------------------------------=
  140. //  CClockControl::StartIdling    
  141. //=--------------------------------------------------------------------------=
  142.  
  143. Boolean8
  144. CClockControl::StartIdling(void)
  145. {
  146.     if (!mIsIdling)
  147.         mIsIdling = mContainerSiteP->SetIdleTime(DefaultIdleTicks, DefaultIdleRefCon) == S_OK;
  148.  
  149.     return mIsIdling;
  150. }
  151.  
  152.  
  153. //=--------------------------------------------------------------------------=
  154. //  CClockControl::StopIdling    
  155. //=--------------------------------------------------------------------------=
  156.  
  157. Boolean8
  158. CClockControl::StopIdling(void)
  159. {
  160.     if (mIsIdling && mContainerSiteP->SetIdleTime(RemoveAllIdlers, NULL) == S_OK)
  161.         mIsIdling = false;
  162.  
  163.     return !mIsIdling;
  164. }
  165.  
  166.  
  167. #pragma mark === CClockControl::private methods ===
  168.  
  169. //=--------------------------------------------------------------------------=
  170. //  CClockControl::DrawAllContexts    
  171. //=--------------------------------------------------------------------------=
  172.  
  173. void
  174. CClockControl::DrawAllContexts()
  175. {
  176.     Boolean8        ShouldBeIdling = false;
  177.     Int32            Index = 1;
  178.     DrawContext        Context = {BeginPortType};
  179.     UInt32            ContextID;
  180.  
  181.     while ( GetContextID(Index, &ContextID) )
  182.     {
  183.         if (mContainerSiteP->AcquireContext(ContextID, &Context) == S_OK)
  184.         {
  185.             //    we could do this by watching context changes, but this is a simple
  186.             //    control which ignores such things - so instead we'll just watch this way
  187.             if (Context.DrawAspect == DVASPECT_CONTENT)
  188.                 ShouldBeIdling = true;
  189.             DrawMe(&Context.Location, Index);
  190.             mContainerSiteP->ReleaseContext(&Context);
  191.         }
  192.         ++Index;
  193.     }
  194.  
  195.     if (ShouldBeIdling != mIsIdling)
  196.     {
  197.         if (ShouldBeIdling)
  198.             StartIdling();
  199.         else
  200.             StopIdling();
  201.     }
  202.  
  203.     mEraseTime = mTime;
  204. }
  205.  
  206.  
  207. //=--------------------------------------------------------------------------=
  208. //  CClockControl::DrawMe    
  209. //=--------------------------------------------------------------------------=
  210.  
  211. void
  212. CClockControl::DrawMe(Rect *BoundsRect, Int32 ContextIndex)
  213. {
  214.     Int16        Pressed;
  215.     Rect        OuterRimRect;
  216.     Rect        InnerRimRect;
  217.     RGBColor    col = { 0 };
  218.     Uint16        height, width;
  219.  
  220.     Int16        ShinyArcAngle    = 15;
  221.     const Int16    PressDistance    = 2;
  222.     const Int16    BorderThickness    = 3;
  223.     const Int16    RimThickness    = 6;
  224.  
  225.  
  226.     //    figure the bounding rectangles
  227.     ::SetRect(&OuterRimRect, BoundsRect->left, BoundsRect->top, BoundsRect->right, BoundsRect->bottom);
  228.     if (mIsPressed)
  229.     {
  230.         Pressed = 1;
  231.         OuterRimRect.top += PressDistance;
  232.         OuterRimRect.left += PressDistance;
  233.     }
  234.     else
  235.     {
  236.         Pressed = 0;
  237.         OuterRimRect.bottom -= PressDistance;
  238.         OuterRimRect.right -= PressDistance;
  239.     }
  240.     InnerRimRect = OuterRimRect;
  241.     ::InsetRect(&InnerRimRect, RimThickness, RimThickness);
  242.         
  243.     if (mFaceDirty == ContextIndex)
  244.     {
  245.         //    clear the whole clock area
  246.         col.red =  col.green = col.blue = Shades[1][Face_Shade];
  247.         ::RGBForeColor(&col);
  248.         {
  249.             Rect    TempRect;
  250.             Int16    Press;
  251.  
  252.             if (Pressed)
  253.                 Press = -PressDistance;
  254.             else
  255.                 Press = PressDistance;
  256.  
  257.             TempRect = OuterRimRect;
  258.             ::OffsetRect(&TempRect, Press, Press);
  259.             ::PaintOval(&TempRect);
  260.         }
  261.         ::PaintOval(&OuterRimRect);
  262.  
  263.         col.red =  col.green = col.blue = Shades[Pressed][Face_Shade];
  264.         ::RGBForeColor(&col);
  265.         ::PaintOval(&OuterRimRect);
  266.  
  267.         //    draw the raised rim
  268.         ::PenSize(RimThickness, RimThickness);
  269.         col.red =  col.green = col.blue = Shades[Pressed][Face_Shade] + 0x1000;
  270.         ::RGBForeColor(&col);
  271.         ::FrameOval(&OuterRimRect);
  272.  
  273.         //    figure out where the specular reflection falls
  274.         height = OuterRimRect.bottom - OuterRimRect.top;
  275.         width = OuterRimRect.right - OuterRimRect.left;
  276.         if (height > width)
  277.             ShinyArcAngle += Uint16((height - width) * 20.0 / height);
  278.         else
  279.             ShinyArcAngle += Uint16((width - height) * 20.0 / width);
  280.  
  281.         //    draw the frame
  282.         ::PenSize(BorderThickness, BorderThickness);
  283.         col.red =  col.green = col.blue = Shades[Pressed][HighKey_Shade];
  284.         ::RGBForeColor(&col);
  285.         ::FrameArc(&OuterRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
  286.         ::FrameArc(&InnerRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
  287.  
  288.         col.red =  col.green = col.blue = Shades[Pressed][HiMedKey_Shade];
  289.         ::RGBForeColor(&col);
  290.         ::FrameArc(&OuterRimRect, ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
  291.         ::FrameArc(&OuterRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
  292.         ::FrameArc(&InnerRimRect, 180 + ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
  293.         ::FrameArc(&InnerRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
  294.  
  295.         col.red =  col.green = col.blue = Shades[Pressed][MedHiKey_Shade];
  296.         ::RGBForeColor(&col);
  297.         ::FrameArc(&OuterRimRect, ShinySpot + 65, 20);
  298.         ::FrameArc(&OuterRimRect, ShinySpot - 65, -20);
  299.         ::FrameArc(&InnerRimRect, 180 + ShinySpot + 65, 20);
  300.         ::FrameArc(&InnerRimRect, 180 + ShinySpot - 65, -20);
  301.  
  302.         col.red =  col.green = col.blue = Shades[Pressed][MedLowKey_Shade];
  303.         ::RGBForeColor(&col);
  304.         ::FrameArc(&OuterRimRect, 180 + ShinySpot + 65, 20);
  305.         ::FrameArc(&OuterRimRect, 180 + ShinySpot - 65, -20);
  306.         ::FrameArc(&InnerRimRect, ShinySpot + 65, 20);
  307.         ::FrameArc(&InnerRimRect, ShinySpot - 65, -20);
  308.  
  309.         col.red =  col.green = col.blue = Shades[Pressed][LowMedKey_Shade];
  310.         ::RGBForeColor(&col);
  311.         ::FrameArc(&OuterRimRect, 180 + ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
  312.         ::FrameArc(&OuterRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
  313.         ::FrameArc(&InnerRimRect, ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
  314.         ::FrameArc(&InnerRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
  315.  
  316.         col.red =  col.green = col.blue = Shades[Pressed][LowKey_Shade];
  317.         ::RGBForeColor(&col);
  318.         ::FrameArc(&OuterRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
  319.         ::FrameArc(&InnerRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
  320.  
  321.         mFaceDirty++;
  322.     }
  323.     else if (mHandsDirty == ContextIndex)
  324.     {
  325.         //    erase the hands
  326.         col.red =  col.green = col.blue = Shades[Pressed][Face_Shade];
  327.         DrawHands(&InnerRimRect, &mEraseTime, &col, true, Pressed);
  328.  
  329.         mHandsDirty++;
  330.     }
  331.  
  332.     //    draw the hands
  333.     {
  334.         col.red =  col.green = col.blue = Shades[Pressed][LowKey_Shade];
  335.         DrawHands(&InnerRimRect, &mTime, &col, false, Pressed);
  336.     }
  337. }
  338.  
  339.  
  340. //=--------------------------------------------------------------------------=
  341. //  CClockControl::DrawMe    
  342. //=--------------------------------------------------------------------------=
  343.  
  344. void
  345. CClockControl::DrawHands(Rect *ClockRect, DateTimeRec *Time, RGBColor *Color, Boolean8 Erasing, Int16 Pressed)
  346. {
  347. #pragma unused (Pressed)
  348.     Int16            Angle, ShinyAngle;
  349.     Int16            X[4];
  350.     Int16            Y[4];
  351.     Int16            i;
  352.     RgnHandle        HandRgn = ::NewRgn();
  353.  
  354.  
  355.     ::PenSize(1, 1);
  356.     ShinyAngle = (450 - ShinySpot) % 360;
  357.  
  358.     for (i = 0; i < 3; i++)
  359.     {
  360.         if (i == 0)
  361.         {
  362.             //    hour hand
  363.             Angle = (450 - (Time->hour % 12) * 30 - Time->minute / 2) % 360;
  364.             FigureHandPoints(Angle, 0.5, 10, ClockRect, X, Y);
  365.         }
  366.         else if (i == 1)
  367.         {
  368.             //    minute hand
  369.             Angle = (450 - Time->minute * 6) % 360;
  370.             FigureHandPoints(Angle, 0.8, 5, ClockRect, X, Y);
  371.         }
  372.         else if (i == 2)
  373.         {
  374.             //    second hand - the really simple case
  375.             Angle = (450 - Time->second * 6) % 360;
  376.             FigureHandPoints(Angle, 0.88, 3, ClockRect, X, Y);
  377.         }
  378.  
  379.         ::OpenRgn();
  380.         ::MoveTo(X[3], Y[3]);
  381.         ::LineTo(X[0], Y[0]);
  382.         ::LineTo(X[1], Y[1]);
  383.         ::LineTo(X[2], Y[2]);
  384.         ::LineTo(X[3], Y[3]);
  385.         ::CloseRgn(HandRgn);
  386.         ::RGBForeColor(Color);
  387.         ::PaintRgn(HandRgn);
  388.         HighlightHands(ShinyAngle, Angle, Color, Erasing, X, Y);    
  389.     }
  390.  
  391.     ::DisposeRgn(HandRgn);
  392. }
  393.  
  394.  
  395. //=--------------------------------------------------------------------------=
  396. //  CClockControl::FigureHandPoints    
  397. //=--------------------------------------------------------------------------=
  398.  
  399. void
  400. CClockControl::FigureHandPoints(Int16 Angle, double LengthPercent, Int16 WidthPixels, Rect *ClockRect, Int16 *XArray, Int16 *YArray)
  401. {
  402.     const double    DegToRad = pi / 180.0;
  403.  
  404.     Int16            CenterX = (Int32(ClockRect->right) + ClockRect->left) / 2;
  405.     Int16            CenterY = (Int32(ClockRect->bottom) + ClockRect->top) / 2;
  406.  
  407.     double            Radians;
  408.     double            Sine, Cosine;
  409.     double            AdjSine, AdjCosine;
  410.     double            XLength, YLength, Ratio, Radius;
  411.  
  412.     {
  413.         Int16    height = ClockRect->bottom - ClockRect->top;
  414.         Int16    width = ClockRect->right - ClockRect->left;
  415.         Ratio = double(height) / (width > 0 ? width : 1);
  416.         Radius = width / 2;
  417.     }
  418.  
  419.     Radians = Angle * DegToRad;
  420.     Cosine = cos(Radians);
  421.     Sine = sin(Radians);
  422.     AdjCosine = Cosine * WidthPixels;
  423.     AdjSine = Sine * WidthPixels;
  424.     XLength = Radius * LengthPercent;
  425.     YLength = XLength * Ratio;
  426.     XArray[3] = CenterX + XLength * Cosine;
  427.     XArray[0] = CenterX - AdjSine;
  428.     XArray[1] = CenterX - AdjCosine;
  429.     XArray[2] = CenterX + AdjSine;
  430.     YArray[3] = CenterY - YLength * Sine;
  431.     YArray[0] = CenterY - AdjCosine;
  432.     YArray[1] = CenterY + AdjSine;
  433.     YArray[2] = CenterY + AdjCosine;
  434. }
  435.  
  436.  
  437. //=--------------------------------------------------------------------------=
  438. //  CClockControl::Reflection    
  439. //=--------------------------------------------------------------------------=
  440.  
  441. Int16 CClockControl::Reflection(Int16 InboundLight, Int16 StartX, Int16 StartY, Int16 EndX, Int16 EndY)
  442. {
  443.     const double    RadToDegrees = 180.0 / pi;
  444.     const double    DegreesToRad = pi / 180.0;
  445.     double            dx, dy;
  446.     Int16            theta, ReturnValue;
  447.  
  448.     dx = EndX - StartX;
  449.     dy = StartY - EndY;
  450.     theta = ::atan(dy/dx) * RadToDegrees;
  451.  
  452.     if (InboundLight > 90)
  453.         InboundLight -= 180;
  454.     else if (InboundLight < -90)
  455.         InboundLight += 180;
  456.     theta -= InboundLight;
  457.     ReturnValue = (::sin(theta * DegreesToRad)) * 256;
  458.     if (ReturnValue < 0)
  459.         ReturnValue *= -1;
  460.  
  461.     return ReturnValue;
  462. }
  463.  
  464.  
  465. //=--------------------------------------------------------------------------=
  466. //  CClockControl::HighlightHands    
  467. //=--------------------------------------------------------------------------=
  468.  
  469. void
  470. CClockControl::HighlightHands(Int16 LightAngle, Int16 HandAngle, RGBColor *Color, Boolean Erasing, Int16 *XArray, Int16 *YArray)
  471. {
  472.     Int16    i, j, DeltaAngle = (360 + LightAngle - HandAngle) % 360;
  473.  
  474.     ::RGBForeColor(Color);
  475.     ::MoveTo(XArray[3], YArray[3]);
  476.     for (i = 0, j = 3; i < 4; j = i, i++)
  477.     {
  478.         if (!Erasing)
  479.         {
  480.             Boolean        Eclipsed = false;
  481.             Int32        Brightness = Reflection(LightAngle, XArray[j], YArray[j], XArray[i], YArray[i]);
  482.             RGBColor    EdgeColor;
  483.  
  484.             if (i == 0 && (DeltaAngle > 175 && DeltaAngle < 355))
  485.                 Eclipsed = true;
  486.             else if (i == 1 && (DeltaAngle > 225 || DeltaAngle < 45))
  487.                 Eclipsed = true;
  488.             else if (i == 2 && (DeltaAngle > 315 || DeltaAngle < 135))
  489.                 Eclipsed = true;
  490.             else if (i == 3 && (DeltaAngle > 5 && DeltaAngle < 185))
  491.                 Eclipsed = true;
  492.  
  493.             if (Eclipsed)
  494.                 Brightness = -Brightness;
  495.  
  496.             EdgeColor.red = EdgeColor.blue = EdgeColor.green = 0x8000 + (127L * Brightness);
  497.             ::RGBForeColor(&EdgeColor);
  498.         }
  499.  
  500.         ::LineTo(XArray[i], YArray[i]);
  501.     }
  502. }
  503.  
  504.